package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.common.constant.Constants;
import cn.itsource.ymcc.common.constant.TaskConstants;
import cn.itsource.ymcc.common.exception.GlobalException;
import cn.itsource.ymcc.common.jwt.JwtUtils;
import cn.itsource.ymcc.common.result.JsonResult;
import cn.itsource.ymcc.common.util.AssertUtil;
import cn.itsource.ymcc.common.util.CodeGenerateUtils;
import cn.itsource.ymcc.domain.KillActivity;
import cn.itsource.ymcc.domain.KillCourse;
import cn.itsource.ymcc.dto.KillDto;
import cn.itsource.ymcc.dto.PreOrderDto;
import cn.itsource.ymcc.mapper.KillActivityMapper;
import cn.itsource.ymcc.service.IKillActivityService;
import cn.itsource.ymcc.service.IKillCourseService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zcj
 * @since 2023-12-12
 */
@Service
public class KillActivityServiceImpl extends ServiceImpl<KillActivityMapper, KillActivity> implements IKillActivityService {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private IKillCourseService killCourseService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public JsonResult getKillCourseList() {
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(TaskConstants.KEY_KILL_COURSE);
        return JsonResult.success().setData(hashOps.values());
    }

    @Override
    public JsonResult getKillCourseDetail(Long courseId) {
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(TaskConstants.KEY_KILL_COURSE);
        return JsonResult.success().setData(hashOps.get(courseId.toString()));
    }

    //抢的是购买资格 --->跳转下单界面 --->点击下单(和之前的下单逻辑一样了)

    //一大堆判断  他秒杀时间在活动时间范围内

    //秒杀减库存
    //生成订单号
    //记录预创订单数据

    @Override
    public JsonResult kill(KillDto killDto, HttpServletRequest request) {
        //获取当前登录人
        JSONObject currentUser = (JSONObject) JwtUtils.getCurrentUser(request.getHeader(Constants.TOKEN));
        Long loginId = ((Integer)currentUser.get("loginId")).longValue();

        //检查用户是否已经购买过
        Boolean b1 = redisTemplate.hasKey(TaskConstants.KILL_RECORD + "_" + loginId + "_" + killDto.getShopId());
        AssertUtil.isFalse(b1,"请不要重复购买");

        //检查数据库
        Date date = new Date();
//        KillCourse killCourse = killCourseService.getById(killDto.getShopId());
//        Long activityId = killCourse.getActivityId();
        //去查询数据库
//        KillActivity one = super.getOne(new LambdaQueryWrapper<KillActivity>().eq(KillActivity::getId, activityId)
//                .le(KillActivity::getBeginTime, date)
//                .ge(KillActivity::getEndTime, date));
//        AssertUtil.isNotNull(one,"秒杀活动已过期");
        //查询redis
        //大key
        BoundHashOperations<String, Object, Object> hashOps =
                redisTemplate.boundHashOps(TaskConstants.KEY_KILL_COURSE);
        KillCourse killCourse = (KillCourse)hashOps.get(killDto.getShopId().toString());
        AssertUtil.isNotNull(killCourse,"秒杀活动已过期");

        //秒杀时间是否合法
        AssertUtil.isTrue(date.after(killCourse.getStartTime())
                && date.before(killCourse.getEndTime()), "秒杀活动时间不合法！");
        //判断购买数量
        Integer number = killDto.getNumber();
        AssertUtil.isTrue(killCourse.getKillLimit()>=number,"超过最大购买数量" );
        //开始抢购
        RSemaphore semaphore = redissonClient.getSemaphore(TaskConstants.KILL_STORE + ":" + killDto.getShopId());
//        semaphore.tryAcquire();//默认减1个
        boolean b = semaphore.tryAcquire(number);//传多少减多少   成功返回true 失败返回false
        String orderNo = CodeGenerateUtils.generateOrderSn(loginId);
        if(b){
            //true 执行创建预订单
            PreOrderDto preOrderDto = new PreOrderDto();
            preOrderDto.setOrderNo(orderNo);
            preOrderDto.setUserId(loginId);
            preOrderDto.setTitle("秒杀订单");
            preOrderDto.setOrderType(1);
            preOrderDto.setPrice(killCourse.getKillPrice());
            preOrderDto.setCount(killDto.getNumber());
            preOrderDto.setCourseId(killCourse.getCourseId());
            preOrderDto.setCourseName(killCourse.getCourseName());
            preOrderDto.setCoursePic(killCourse.getCoursePic());
            preOrderDto.setKillCourseId(killCourse.getId());

            redisTemplate.opsForValue().set(TaskConstants.KEY_PREFIX_PRE_ORDER+":"+orderNo, preOrderDto);

            //5. 发送延迟消息到MQ，用作下单超时处理（5分钟）：【消费者写在订单服务中】5分钟后用户仍未下单（通过订单编号去查询订单表），则取消资格【通过订单编号为key删除redis中保存的预创订单】
            rocketMQTemplate.syncSend(
                    TaskConstants.TOPIC_ORDER_TIMEOUT+":"+TaskConstants.TAGS_ORDER_TIMEOUT,
                    MessageBuilder.withPayload(orderNo).build(),
                    3000, 5);//9
            //6. 保存用户秒杀记录到Redis防止重复秒杀  KILL_RECORD_用户id_秒杀课程id =》 value随意
            redisTemplate.opsForValue().set(TaskConstants.KILL_RECORD+"_"+loginId+"_"+killDto.getShopId(),"0");
        }else {
            throw new GlobalException("秒杀失败！");
        }
        return JsonResult.success().setData(orderNo);
    }
}
